#include "zrpc/base/thread_pool.h"

#include "zrpc/base/thread.h"
#include "zrpc/net/event_loop.h"
namespace zrpc {

ThreadPool::ThreadPool(EventLoop *base_loop_)
    : base_loop_(base_loop_), started_(false), num_threads_(0), next_(0) {}

ThreadPool::~ThreadPool() { threads_.clear(); }

void ThreadPool::Start(const ThreadInitCallback &cb) {
  assert(!started_);
  base_loop_->AssertInLoopThread();

  started_ = true;

  for (int i = 0; i < num_threads_; i++) {
    std::shared_ptr<Thread> t(new Thread(cb));
    threads_.push_back(t);
    loops_.push_back(t->StartLoop());
  }

  if (num_threads_ == 0 && cb) {
    cb(base_loop_);
  }
}

EventLoop *ThreadPool::GetNextLoop() {
  assert(started_);
  EventLoop *loop = base_loop_;

  if (!loops_.empty()) {
    loop = loops_[next_];
    ++next_;
    if (next_ >= loops_.size()) {
      next_ = 0;
    }
  }
  return loop;
}

EventLoop *ThreadPool::GetBaseLoop() { return base_loop_; }

EventLoop *ThreadPool::GetLoopForHash(size_t hash_code) {
  base_loop_->AssertInLoopThread();
  EventLoop *loop = base_loop_;

  if (!loops_.empty()) {
    loop = loops_[hash_code % loops_.size()];
  }
  return loop;
}

std::vector<EventLoop *> ThreadPool::GetAllLoops() {
  assert(started_);
  if (loops_.empty()) {
    return std::vector<EventLoop *>(1, base_loop_);
  } else {
    return loops_;
  }
}
}  // namespace zrpc